﻿using Microsoft.Extensions.DependencyInjection;
using Modules.Person.Repositories;
using PmSoft;
using System.Collections.Concurrent;
using System.Collections.Generic;

namespace Modules.Person;

/// <summary>
/// 人员身份证号码主键索引器
/// </summary>
[UseDI(ServiceLifetime.Scoped)]
public class PersonIdCardIndexer
{
    private static readonly ConcurrentDictionary<int, string> idToKeyDict = new();
    private static readonly ConcurrentDictionary<string, int> keyToIdDict = new();
    private static readonly SemaphoreSlim _lock = new(initialCount: 1, maxCount: 1);

    private readonly PersonInfoRepository personInfoRepository;

    public PersonIdCardIndexer(PersonInfoRepository personInfoRepository)
    {
        this.personInfoRepository = personInfoRepository;
    }

    /// <summary>
    /// 根据专户ID获取专户账号
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    public string GetIdCard(int id)
    {
        if (idToKeyDict.TryGetValue(id, out string? idCard))
            return idCard;

        try
        {
            _lock.Wait();

            if (idToKeyDict.TryGetValue(id, out idCard))
                return idCard;

            var personInfo = personInfoRepository.Get(id);
            if (personInfo != null
                && !string.IsNullOrEmpty(personInfo.CardNumber)
                && idToKeyDict.TryAdd(id, personInfo.CardNumber))
            {
                return personInfo.CardNumber;
            }
            return string.Empty;
        }
        finally
        {
            _lock.Release();
        }
    }

    /// <summary>
    /// 根据身份证号码获取人员ID
    /// </summary>
    /// <param name="idCard"></param>
    /// <returns></returns>
    public int? GetId(string idCard)
    {
        if (keyToIdDict.TryGetValue(idCard, out int id))
            return id;
        try
        {
            _lock.Wait();

            if (keyToIdDict.TryGetValue(idCard, out id))
                return id;

            int? personId = personInfoRepository.GetPersonIdByCardNo(idCard);
            if (personId.HasValue && personId > 0 && keyToIdDict.TryAdd(idCard, personId.Value))
                return personId.Value;

            return null;
        }
        finally
        {
            _lock.Release();
        }
    }

    public bool Remove(int id)
    {
        if (idToKeyDict.TryRemove(id, out string? key)
            && keyToIdDict.TryRemove(key, out _))
            return true;
        return false;
    }

}
